package cn.song.util.easyexcel.model;

import cn.song.model.R;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;

import static cn.hutool.json.JSONUtil.toJsonStr;

/**
 * 批次计数
 *
 * @author SongRenShuo
 * @date 2024/02/04
 */
@Data
@Slf4j
@Builder
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class BatchCount {

    /**
     * 成功计数
     */
    private int successCount;
    /**
     * 错误计数
     */
    private int errorCount;
    /**
     * 总数
     */
    private int totalCount;
    /**
     * 错误消息
     */
    @Builder.Default
    private List<BatchCountDto> errorMsg = new ArrayList<>();

    public BatchCount(int totalCount) {
        this.totalCount = totalCount;
    }


    /**
     * 处理成功插入
     *
     * @param batchCountDtos 地图列表
     * @param sCount  失败条数
     * @param orderId 订单号
     * @date 2024/05/30
     * @author SongRenShuo
     */
    public static void handleSuccessfulInsert(ArrayList<BatchCountDto> batchCountDtos, int sCount, String orderId) {
        // batchCountDtos.add(BatchCountDto.builder().orderId(orderId).state("error").msg("成功，订单号：" + orderId).build());
    }

    /**
     * 处理成功插入
     *
     * @param batchCountDtos 地图列表
     * @param sCount  失败条数
     * @param orderId 订单号
     * @param whetherItIsRecorded 是否记录
     * @param successMsg 成功描述
     * @date 2024/05/30
     * @author SongRenShuo
     */
    public static void handleSuccessfulInsert(ArrayList<BatchCountDto> batchCountDtos, int sCount, String orderId,Boolean whetherItIsRecorded, String successMsg) {
        if (whetherItIsRecorded!=null && whetherItIsRecorded){
            batchCountDtos.add(BatchCountDto.builder().orderId(orderId).state("success").msg( successMsg).build());
        }
    }
    /**
     * 处理失败插入
     *
     * @param batchCountDtos  地图列表
     * @param eCount   成功条数
     * @param orderId  订单号
     * @param errorMsg 错误消息
     * @date 2024/05/30
     * @author SongRenShuo
     */
    public static void handleFailedInsert(ArrayList<BatchCountDto> batchCountDtos, int eCount, String orderId, String errorMsg) {

        handleFailedInsert(batchCountDtos, eCount, orderId, null, errorMsg);
    }
    /**
     * 处理失败插入
     *
     * @param batchCountDtos  地图列表
     * @param eCount   成功条数
     * @param orderId  订单号
     * @param e 错误消息
     * @date 2024/05/30
     * @author SongRenShuo
     */
    public static void handleFailedInsert(ArrayList<BatchCountDto> batchCountDtos, int eCount, String orderId, Throwable e) {

        handleFailedInsert(batchCountDtos, eCount, orderId, null, e);
    }

    /**
     * 处理失败插入
     *
     * @param batchCountDtos  地图列表
     * @param eCount   成功条数
     * @param orderId  订单号
     * @param errorMsg 错误消息
     * @date 2024/05/30
     * @author SongRenShuo
     */
    public static void handleFailedInsert(ArrayList<BatchCountDto> batchCountDtos, int eCount, String orderId, Object data, String errorMsg) {
        batchCountDtos.add(BatchCountDto.builder().orderId(orderId).state("error").msg(errorMsg).build());
        log.error("批量操作时单条失败,订单号【{}】,具体原因：{},具体参数：{}", orderId, errorMsg, toJsonStr(data));
    }
    /**
     * 处理失败插入
     *
     * @param batchCountDtos  地图列表
     * @param eCount   成功条数
     * @param orderId  订单号
     * @param e 错误消息
     * @date 2024/05/30
     * @author SongRenShuo
     */
    public static void handleFailedInsert(ArrayList<BatchCountDto> batchCountDtos, int eCount, String orderId, Object data, Throwable e) {
        String errorMsg = e.getMessage();
        batchCountDtos.add(BatchCountDto.builder().orderId(orderId).state("error").msg(errorMsg).build());
        log.error("批量操作时单条失败,订单号【{}】,具体原因：{},具体参数：{}", orderId, errorMsg, toJsonStr(data),e);
    }

    /**
     * 通用批量处理方法  - 未出现异常视为成功
     *
     * @param dingdanhaos 订单号列表
     * @param param 参数 - 只记录日志
     * @param serviceMethod 服务方式
     * @param actionDescription 操作说明
     * @param paramDescription 参数描述
     * @date 2025/04/12
     * @author SongRenShuo
     * @return {@link R }<{@link BatchCount }>
     */
    public static R<BatchCount> batchProcess(List<String> dingdanhaos, String param,
                                       BiConsumer<String, String> serviceMethod,
                                       String actionDescription, String paramDescription) {
        int sCount = 0;
        int eCount = 0;
        ArrayList<BatchCountDto> errorMsg = new ArrayList<>();
        for (String dingdanhao : dingdanhaos) {
            try {
                serviceMethod.accept(dingdanhao, param);
                BatchCount.handleSuccessfulInsert(errorMsg, sCount++, dingdanhao);
            } catch (Exception e) {
                BatchCount.handleFailedInsert(errorMsg, eCount++, dingdanhao, param, e);
            }
        }
        BatchCount batchCount = new BatchCount(dingdanhaos.size());
        batchCount.setSuccessCount(sCount);
        batchCount.setErrorCount(eCount);
        batchCount.setErrorMsg(errorMsg);
        R<BatchCount> success = R.success(batchCount);
        log.info("批量 - {}，订单号列表为：{},{}为：{},执行结果为：{}", actionDescription, dingdanhaos, paramDescription, param, toJsonStr(success));
        return success;
    }

    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public static class BatchCountDto {

        /**
         * 订单号
         */
        @ExcelProperty("订单号")
        private String orderId;
        /**
         * 执行结果(success/成功,error/失败)
         */
        @ExcelProperty("执行结果(success/成功,error/失败)")
        private String state;
        /**
         * 描述
         */
        @ExcelProperty("描述")
        private String msg;
    }
}
